#pragma once

#include <unistd.h>
#include <signal.h>
#include <cstdlib>
#include <cassert>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define DEV "/dev/null"

void daemonSelf(const char *cwd = nullptr)
{
    // 1.让调用进程忽略掉异常的信号
    //(服务器再响应客户端请求,返回给客户端数据的时候,客户端崩溃读端关闭,服务器写端继续写会收到SIGPIPE信号,服务器冤死了,你客户端崩了捎带着把我也搞崩了,无语了家人们)
    signal(SIGPIPE, SIG_IGN);//客户端关闭服务器不受影响

    // 2.如何让进程自己不是组长, 然后调用setsid(组长不能走啊, 要不然组员咋办啊!)
    if(fork() > 0) exit(0);
    // 子进程 -- 守护进程, 精灵进程, 本质就是孤儿进程的一种
    pid_t n = setsid();
    assert(n != -1);

    // 3.守护进程是脱离终端的自成的一个会话, 关闭或者重定向以前进程默认打开的文件描述符(012)
    // 关掉文件描述符这种方案不好,因为其他进程再调用daemon.hpp进行守护进程化之后,他们就变成子进程了,而此时这些调用组件的进程就无法使用012fd了,如果此时其他调用
    //组件的进程不小心使用了012fd, 那么此时进程就会立即出错,服务器进程就挂掉了
    // 所以我们应该使用更温和的做法: 把012重定向到/dev/null 则对012的操作全部被丢弃
    int fd = open(DEV, O_RDWR);
    if(fd >= 0)
    {
        //重定向
        dup2(fd, 0);// int dup2(int oldfd, int newfd); 新的是旧的copy 所以newfd的新的struct file*地址变为fd指向的struct file*地址 也就是文件黑洞地址
        dup2(fd, 1);
        dup2(fd, 2);
    
        close(fd);
    }
    else
    {
        //没办法重定向了,只能关闭012
        close(0);
        close(1);
        close(2);
    }

    // 4.可选: 进程执行路径发生更改
    if(cwd != nullptr) chdir(cwd);
}


